﻿using NPOI.OpenXmlFormats.Spreadsheet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Shapes;
using static LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets.MindMap.MindMapView;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets.MindMap
{
    /// <summary>
    /// 导图元素类别枚举。
    /// </summary>
    public enum TreeElementType
    {
        /// <summary>
        /// 一般的Title，其中的内容就是纯文本。
        /// </summary>
        Text,
        /// <summary>
        /// 图像链接元素。
        /// </summary>
        ImageLink,
        /// <summary>
        /// 文档链接元素。
        /// </summary>
        FileLink,
    }

    public class TreeElement
    {
        public TreeElement(RootElement rootElement, TreeElement parentElement, string content, int level, string markdownFilePath)
        {
            RootElement = rootElement;
            ParentElement = parentElement;
            this.masterMarkdownFilePath = markdownFilePath;
            Level = level;

            var reg = new Regex(@"^[:：][ 　\t]{0}?[\[【][ 　\t]{0}?[ltrb左上右下*＊\-－\+＋=＝<>＜＞《〈〉》\{\}｛｝][ 　\t]{0}?[\]】][ 　\t]{0}?");
            if (string.IsNullOrWhiteSpace(content) == false)
            {
                var match = reg.Match(content);
                if (match.Success)
                {
                    var mark = match.Value.Trim(new char[] { ' ', '　', '\t', '[', ']', ':', '：', '【', '】' });
                    switch (mark)
                    {
                        case "l":
                        case "左":
                        case "}":
                        case "｝":
                            {
                                this.viewType = MindMapView.ViewType.OrgLeft; break;
                            }
                        case "t":
                        case "上":
                            {
                                this.viewType = MindMapView.ViewType.OrgUp; break;
                            }
                        case "r":
                        case "右":
                        case "{":
                        case "｛":
                            {
                                this.viewType = MindMapView.ViewType.OrgRight; break;
                            }
                        case "d":
                        case "下":
                            {
                                this.viewType = MindMapView.ViewType.OrgDown; break;
                            }
                        case "*":
                        case "＊":
                            {
                                this.viewType = MindMapView.ViewType.Default; break;
                            }
                        case "-":
                        case "－":
                            {
                                this.viewType = MindMapView.ViewType.List; break;
                            }
                        case "+":
                        case "＋":
                        case "=":
                        case "＝":
                            {
                                this.viewType = MindMapView.ViewType.ListOfAncestors; break;
                            }
                        case "<":
                        case "＜":
                        case "《":
                        case "〈":
                            {
                                this.viewType = MindMapView.ViewType.LeftFish; break;
                            }
                        case ">":
                        case "＞":
                        case "〉":
                        case "》":
                            {
                                this.viewType = MindMapView.ViewType.RightFish; break;
                            }
                        default:
                            {
                                this.viewType = null; break;
                            }
                    }
                    content = content.Substring(match.Length);
                }
            }

            if (level == 0 && this.viewType == MindMapView.ViewType.ListOfAncestors)
            {
                this.viewType = MindMapView.ViewType.List;  // 顶级标题不允许设置“祖先级列表”，用近似的“列表”代替。
            }

            if (CustomMarkdownSupport.IsImageGroupLinkLine(content, out string word1, out string path1, out string word2))
            {
                if (string.IsNullOrWhiteSpace(path1) == false && string.IsNullOrWhiteSpace(masterMarkdownFilePath) == false)
                {
                    this.Content = word1;
                    this.relativePath = path1;
                    this.linkedImageRealPath = Utils.ImageLinkTool.GetRealPathFromRelativePath(path1, masterMarkdownFilePath);
                    // 忽略这个：this.commentTextBlock.Text = word2;
                    this.Type = TreeElementType.ImageLink;
                }
                else
                {
                    Content = content;
                    this.Type = TreeElementType.Text;
                }
            }
            else if (CustomMarkdownSupport.IsFileLinkLine(content, out string word3, out string path2, out string word4))
            {
                if (string.IsNullOrWhiteSpace(path2) == false && string.IsNullOrWhiteSpace(masterMarkdownFilePath) == false)
                {
                    this.Content = word3;
                    this.relativePath = path2;
                    this.linkedFileRealPath = Utils.ImageLinkTool.GetRealPathFromRelativePath(path2, masterMarkdownFilePath);
                    this.Type = TreeElementType.FileLink;
                }
                else
                {
                    Content = content;
                    this.Type = TreeElementType.Text;
                }
            }
            else
            {
                Content = content;
                this.Type = TreeElementType.Text;
            }
        }

        private ViewType? viewType = null;

        public ViewType? ViewType
        {
            get { return viewType; }
        }

        private string masterMarkdownFilePath;

        public string MasterMarkdownFilePath
        {
            get { return masterMarkdownFilePath; }
        }

        public TreeElementType Type { get; set; } = TreeElementType.Text;

        private string relativePath;
        /// <summary>
        /// 链接到的资源文件（或图像文件）的相对路径。
        /// </summary>
        public string RelativePath
        {
            get
            {
                return this.relativePath;
            }
        }

        private string linkedImageRealPath;
        /// <summary>
        /// 链接的图像资源文件的真实路径。
        /// </summary>
        public string LinkedImageRealPath
        {
            get { return linkedImageRealPath; }
        }

        private string linkedFileRealPath;
        /// <summary>
        /// 链接的 Markdown 文件的真实路径。
        /// </summary>
        public string LinkdeFileRealPath
        {
            get { return linkedFileRealPath; }
        }

        /// <summary>
        /// 一个树型文字表可能包括多个根节点，故应返回根节点列表。
        /// 每个根节点（及其下的子级节点）共同构成一幅思维导图。
        /// </summary>
        /// <param name="lines"></param>
        /// <param name="allElements">这个列表不递归，找 FriendElement 时直接循环就可以，效率更高。</param>
        /// <returns>返回的是 RootElements。</returns>
        public static List<TreeElement> ParseRootTreeElementsFromTreeTables(List<List<string>> treeTables, out List<TreeElement> allElements, string markdownFilePath)
        {
            List<TreeElement> rootElements = new List<TreeElement>();
            allElements = new List<TreeElement>();

            RootElement newRootElement = null;
            TreeElement previewElement = null;
            foreach (var treeTable in treeTables)
            {
                if (treeTable.Count <= 0) continue;
                foreach (var treeLine in treeTable)
                {
                    if (CustomMarkdownSupport.IsTreeListTextLine(treeLine, out string header, out string tail, out int level) == false)
                    {
                        continue;
                    }
                    if (level < 1) continue;

                    if (level == 1)
                    {
                        newRootElement = new RootElement(tail, markdownFilePath);
                        rootElements.Add(newRootElement);
                        allElements.Add(newRootElement);
                        previewElement = newRootElement;
                        continue;
                    }

                    if (previewElement != null)
                    {
                        if (level == previewElement.Level)
                        {
                            if (previewElement.ParentElement != null)
                            {
                                var newElement = new TreeElement(newRootElement, previewElement.ParentElement, tail, level, markdownFilePath);
                                previewElement.ParentElement.Children.Add(newElement);
                                allElements.Add(newElement);
                                previewElement = newElement;
                                continue;
                            }
                        }
                        else if (level >= previewElement.Level + 1)
                        {
                            var newElement = new TreeElement(newRootElement, previewElement, tail, previewElement.Level + 1, markdownFilePath);
                            previewElement.Children.Add(newElement);
                            allElements.Add(newElement);
                            previewElement = newElement;
                            continue;
                        }
                        else
                        {
                            // 级别小于前一个，可能小好几级
                            // 沿着 previewElement 向上找，直到找到级别为 level -1 的那个节点
                            var preParentElement = previewElement.ParentElement;
                            while (preParentElement != null && preParentElement.Level > level - 1)
                            {
                                preParentElement = preParentElement.ParentElement;
                            }

                            var newElement = new TreeElement(newRootElement, preParentElement, tail, level, markdownFilePath);
                            preParentElement.Children.Add(newElement);
                            allElements.Add(newElement);
                            previewElement = newElement;
                            continue;
                        }
                    }
                    // 由于树型文字表自带格式化功能，所以理论上，poreviewElement 为 null 的情况只应该是根元素才会碰到
                }
            }

            return rootElements;
        }

        public List<TreeElement> Children { get; } = new List<TreeElement>();

        /// <summary>
        /// 递归获取当前元素所有后裔元素。
        /// </summary>
        /// <returns></returns>
        public static void GetDescendant(ref List<TreeElement> list, TreeElement element)
        {
            if (element == null || list == null || element.Children.Count <= 0) return;

            foreach (var child in element.Children)
            {
                list.Add(child);
                GetDescendant(ref list, child);
            }
        }

        /// <summary>
        /// 跨结构的链接。
        /// </summary>
        public List<TreeElement> Friends { get; set; } = null;

        public TreeElement PreviewElement
        {
            get
            {
                if (this.ParentElement == null || this.ParentElement.Children == null || this.ParentElement.Children.Count <= 0) return null;

                var index = this.ParentElement.Children.IndexOf(this);
                if (index >= 1)
                {
                    return this.ParentElement.Children[index - 1];
                }

                return null;
            }
        }

        /// <summary>
        /// 没有的话返回 null。
        /// </summary>
        public List<TreeElement> PreviewElements
        {
            get
            {
                if (this.ParentElement == null || this.ParentElement.Children == null || this.ParentElement.Children.Count <= 0) return null;

                var index = this.ParentElement.Children.IndexOf(this);
                if (index <= 0) return null;

                var preElements = new List<TreeElement>();
                for (int i = 0; i < index; i++)
                {
                    preElements.Add(this.ParentElement.Children[i]);
                }

                return preElements;
            }
        }

        public TreeElement NextElement
        {
            get
            {
                if (this.ParentElement == null || this.ParentElement.Children == null || this.ParentElement.Children.Count <= 0) return null;

                var index = this.ParentElement.Children.IndexOf(this);
                if (index >= 0 && index < this.ParentElement.Children.Count - 1)
                {
                    return this.ParentElement.Children[index + 1];
                }

                return null;
            }
        }

        public List<TreeElement> NextElements
        {
            get
            {
                if (this.ParentElement == null || this.ParentElement.Children == null || this.ParentElement.Children.Count <= 0) return null;

                var index = this.ParentElement.Children.IndexOf(this);
                if (index < 0 || index >= this.ParentElement.Children.Count - 1) return null;

                var preElements = new List<TreeElement>();
                for (int i = index + 1; i < this.ParentElement.Children.Count; i++)
                {
                    preElements.Add(this.ParentElement.Children[i]);
                }

                return preElements;
            }
        }

        private int Level { get; set; } = 0;

        public int Add(TreeElement newElement)
        {
            this.Children.Add(newElement);
            return this.Children.Count - 1;
        }

        public void Remove(TreeElement element)
        {
            if (this.Children.Contains(element))
            {
                this.Children.Remove(element);
            }
        }

        public void RemoveAt(int index)
        {
            if (index >= 0 && index < this.Children.Count)
            {
                this.Children.RemoveAt(index);
            }
        }

        public RootElement RootElement { get; set; } = null;

        public TreeElement ParentElement { get; set; } = null;

        public string Content { get; set; } = string.Empty;
    }

}
